import { Injectable, Inject, BadRequestException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

import { Schema } from 'mongoose';
import * as md5 from 'md5';
import * as dayjs from 'dayjs';
import { ensureDirSync, writeFileSync, readFileSync } from 'fs-extra';
import { join, extname } from 'path';
import { nanoid } from 'nanoid';

import { FileModel } from '@server/models';
import { AuthService } from '@server/auth';

import { GetFileDetailType, UploadFileDto, UploadFileResponse } from './dto';
import { FILE_NOT_EXIST } from './error';

@Injectable()
export default class FileService {
  constructor(
    private readonly configService: ConfigService,
    private readonly authService: AuthService,
    @Inject('FILE_MODEL') private readonly fileModel: typeof FileModel,
  ) {}

  async upload(file: UploadFileDto): Promise<UploadFileResponse> {
    const bufferString: string = file.buffer.toString('utf8');
    const fileMd5: string = md5(bufferString);
    const now: dayjs.Dayjs = dayjs();
    const fileExtension: string = extname(file.originalname);

    const fileName: string = `${now.unix()}-${nanoid(10)}${fileExtension}`;
    const folderPath: string = join(
      this.configService.get('publicPath'),
      `files-${now.format('YYYY-MM-DD')}`,
    );
    const storagePath: string = join(folderPath, fileName);

    const { id } = await this.fileModel.create({
      fileName,
      storagePath,
      md5: fileMd5,
      size: file.size,
      mime: file.mimetype,
    });

    ensureDirSync(folderPath);
    writeFileSync(storagePath, file.buffer);

    return {
      code: 0,
      message: '',
      data: {
        url: `${this.configService.get('domain')}/file/${id}`,
      },
    };
  }

  async detail(id: string): Promise<GetFileDetailType> {
    const file: any = await this.fileModel.findById(id, [
      'mime',
      'storagePath',
    ]);
    if (!file) {
      throw new BadRequestException(FILE_NOT_EXIST);
    } else {
      return {
        mime: file.mime,
        buffer: readFileSync(file.storagePath),
      };
    }
  }
}
